package com.seanLab.tool.es;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.seanLab.dao.ImageDao;
import com.seanLab.domain.Image;
import org.apache.lucene.search.join.ScoreMode;
import org.elasticsearch.action.admin.indices.mapping.put.PutMappingRequest;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchType;
import org.elasticsearch.client.Requests;
import org.elasticsearch.client.transport.TransportClient;
import org.elasticsearch.common.network.InetAddresses;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.transport.InetSocketTransportAddress;
import org.elasticsearch.common.xcontent.XContentBuilder;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.index.query.NestedQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.query.TermQueryBuilder;
import org.elasticsearch.index.query.functionscore.FunctionScoreQueryBuilder;
import org.elasticsearch.index.query.functionscore.ScoreFunctionBuilders;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.DeleteByQueryAction;
import org.elasticsearch.search.aggregations.AggregationBuilders;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregationBuilder;
import org.elasticsearch.search.aggregations.bucket.nested.NestedAggregator;
import org.elasticsearch.transport.client.PreBuiltTransportClient;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.InetAddress;
import java.util.List;

/**
 * Created by mac on 17/9/5.
 */
@Component
@ConfigurationProperties(prefix = "com.dasLab.es")
public class ImageTagDao {
    //使用配置文件自动注入属性
   // @Value("${es.host:localhost}")
    private String host="localhost";

  //  @Value("${es.port:9300}")
  //  private String s_port;

    //    private int port = Integer.parseInt(s_port);
    private int port;

  //  @Value("${es.index:tag}")
    private String index="tag";

   // @Value("${es.type:chnTag}")
    private String type="chnTag";

    private TransportClient client;

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public TransportClient getClient() {
        return client;
    }

    public void setClient(TransportClient client) {
        this.client = client;
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public String getIndex() {
        return index;
    }

    public void setIndex(String index) {
        this.index = index;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

    public ImageTagDao(){
//        initConnection(host, port);
    }

    public void initConnection(String host, int port){
        try {
            this.client = new PreBuiltTransportClient(Settings.EMPTY)
                    .addTransportAddress(new InetSocketTransportAddress(InetAddress.getByName(host), port));
//.addTransportAddress(new InetSocketTransportAddress(InetAddresses.forString("127.0.0.1"), port));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public int insertImage(Image img) {
//        String json=ImageTag.buildJsonFromImage(img);//TODO
        String json=UtilJson.json2Image(img);
        IndexResponse response = indexsDocument(index, type,json);
        return response.status().getStatus();
    }

    public IndexResponse indexsDocument(String index, String type, String jsonDoc){
        if (client == null) {
            System.out.println("Null TransportClient");
            return null;
        } else {
            IndexResponse indexResponse = client.prepareIndex(index, type).setSource(jsonDoc).get();
//            System.out.println(indexResponse.toString());
            return indexResponse;
        }
    }

    public int update(Image img) {//todo
        return 0;
    }

    public String delete(String imgID) {//todo
        BulkByScrollResponse response =
                DeleteByQueryAction.INSTANCE.newRequestBuilder(client)
                        .filter(QueryBuilders.termQuery("img_id", imgID))
                        .source(index)
                        .get();
//        DeleteResponse response = client.prepareDelete(index, type, ).get();
        System.out.println(response.toString());
        return response.toString();
    }

    public String searchWithKeys(List<String> tagsList, int resultNum) {
        String searchKeyWords=getKeyWords(tagsList);

        FunctionScoreQueryBuilder query =
                QueryBuilders.functionScoreQuery(QueryBuilders.matchQuery("Tags.tag_name",searchKeyWords),
                        ScoreFunctionBuilders.fieldValueFactorFunction("Tags.tag_score"));
        System.out.println(query.toString());
        SearchResponse response = client.prepareSearch(index)
                .setTypes(type)
                .setQuery(QueryBuilders.nestedQuery("Tags", query , ScoreMode.Total))
                .setSize(resultNum)
                .get();
        return response.toString();
    }

    public String searchMacthAll() {//todo
        SearchResponse testr = client.prepareSearch("tag")
                .setTypes("chnTag")
                .setQuery(QueryBuilders.matchAllQuery()).get();
        return testr.toString();
    }

    public String facetSeach(List<String> tagsList, int resultNum, String name, String field){ //TODO
        String searchKeyWords=getKeyWords(tagsList);
        FunctionScoreQueryBuilder query =
                QueryBuilders.functionScoreQuery(QueryBuilders.matchQuery("Tags.tag_name",searchKeyWords),
                        ScoreFunctionBuilders.fieldValueFactorFunction("Tags.tag_score"));

        SearchResponse response = client.prepareSearch(index)
                .setTypes(type)
                .setQuery(QueryBuilders.nestedQuery("Tags", query , ScoreMode.Total))
                .addAggregation(AggregationBuilders.terms(name).field(field))
                .setSize(resultNum)
                .execute().actionGet();

        return response.toString();
    }

    public String facetSeachPostFilter(List<String> tagsList, String filter, int resultNum, String name, String field){ //TODO
        String searchKeyWords=getKeyWords(tagsList);

//-------------search result
        FunctionScoreQueryBuilder query =
                QueryBuilders.functionScoreQuery(QueryBuilders.matchQuery("Tags.tag_name",searchKeyWords),
                        ScoreFunctionBuilders.fieldValueFactorFunction("Tags.tag_score"));
//
        TermQueryBuilder pf = QueryBuilders.termQuery(field,filter);

        SearchResponse response = client.prepareSearch(index)
                .setTypes(type)
                .setQuery(QueryBuilders.nestedQuery("Tags", query , ScoreMode.Total))
                .addAggregation(AggregationBuilders.terms(name).field(field))
                .setPostFilter(pf)
                .setSize(resultNum)
                .execute().actionGet();

        return response.toString();
    }

    public String nestedFacetSearch(List<String> tagsList, int resultNum, String path, String field,String name1,String name2,String name3) {
        String searchKeyWords=getKeyWords(tagsList);
        FunctionScoreQueryBuilder query =
                QueryBuilders.functionScoreQuery(QueryBuilders.matchQuery("Tags.tag_name",searchKeyWords),
                        ScoreFunctionBuilders.fieldValueFactorFunction("Tags.tag_score"));

        NestedAggregationBuilder ab=AggregationBuilders.nested(name1,path).subAggregation(AggregationBuilders.terms(name2).field(field).subAggregation(AggregationBuilders.reverseNested(name3)));
        SearchResponse response = client.prepareSearch(index)
                .setTypes(type)
                .setQuery(QueryBuilders.nestedQuery("Tags", query , ScoreMode.Total))
                .addAggregation(ab)
                .setSize(resultNum)
                .execute().actionGet();
        return response.toString();
    }

    /**
     *
     * @param tagsList 输入的用来搜索的关键词
     * @param filter 搜索结果根据该bucket来过滤
     * @param resultNum 搜索结果的数量
     * @param field 根据field来进行聚合
     * @param name1
     * @param name2
     * @param name3
     * @return
     */
    public String nestedFacetSearchPostFilter(List<String> tagsList, String filter, int resultNum, String field,String name1,String name2,String name3) {
        String searchKeyWords=getKeyWords(tagsList);
//        String path="Tags";
        FunctionScoreQueryBuilder query =
                QueryBuilders.functionScoreQuery(QueryBuilders.matchQuery("Tags.tag_name",searchKeyWords),
                        ScoreFunctionBuilders.fieldValueFactorFunction("Tags.tag_score"));

        NestedAggregationBuilder na= AggregationBuilders.nested(name1,"Tags").subAggregation(AggregationBuilders.terms(name2).field(field).subAggregation(AggregationBuilders.reverseNested(name3)));


        NestedAggregationBuilder ab =
                AggregationBuilders.nested(name1,"Tags").subAggregation(AggregationBuilders.terms(name2).field(field).subAggregation(AggregationBuilders.reverseNested(name3)));

        NestedQueryBuilder pf =
                QueryBuilders.nestedQuery("Tags",QueryBuilders.termQuery("Tags.tag_source",filter),ScoreMode.None);

        SearchResponse response = client.prepareSearch(index)
                .setTypes(type)
                .setQuery(QueryBuilders.nestedQuery("Tags", query , ScoreMode.Total)).setSearchType(SearchType.DFS_QUERY_THEN_FETCH)
                .addAggregation(ab)
                .setPostFilter(pf)
                .setSize(resultNum)
                .execute().actionGet();
        return response.toString();
    }

    private String getKeyWords(List<String> tagsList) {
        String ret="";
        for (int i=0;i<tagsList.size();i++){
            ret+=tagsList.get(i)+" ";
        }
        if (ret.length()>0){
            ret=ret.substring(0,ret.length()-1);
        }
        return ret;
    }

}
